home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xconq / phases.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  16KB  |  535 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. #pragma comment(exestr, "@(#) phases.c 12.1 95/05/09 ")
  6.  
  7. /* RCS $Header: phases.c,v 1.3 88/07/20 14:35:19 shebs Exp $ */
  8.  
  9. /* This file includes all turn phases except init, movement, and endgame. */
  10.  
  11. #include "config.h"
  12. #include "misc.h"
  13. #include "dir.h"
  14. #include "period.h"
  15. #include "side.h"
  16. #include "unit.h"
  17. #include "map.h"
  18. #include "global.h"
  19.  
  20. /* Should probably be in period.h */
  21.  
  22. #define will_garrison(u1, u2) (utypes[u1].guard[u2] > 0)
  23.  
  24. bool anyrevolt = FALSE;
  25. bool anysurrender = FALSE;
  26. bool anyaccident = FALSE;
  27. bool anyattrition = FALSE;
  28.  
  29. /* Spying phase reveals other sides' secrets.  This phase also automatically */
  30. /* updates allies's view of each other's units; not every turn, but fairly */
  31. /* regularly (can do briefing at any time, of course).  Spying will reveal */
  32. /* hex even if never seen before (dubious). */
  33.  
  34. spy_phase()
  35. {
  36.     Side *side, *other;
  37.  
  38.     if (Debug) printf("Entering spy phase\n");
  39.     for_all_sides(side) {
  40.     if (probability(period.spychance)) {
  41.         other = side_n(random(numsides));
  42.         if (other != NULL && !other->lost && !allied_side(side, other)) {
  43.         if (period.spychance < 20) {
  44.             notify(side, "You found out some of the %s dispositions!!",
  45.                other->name);
  46.         }
  47.         reveal_side(other, side, period.spyquality);
  48.         }
  49.     }
  50.     for_all_sides(other) {
  51.         if (allied_side(other, side) && side != other && probability(20)) {
  52.         reveal_side(side, other, 100);
  53.         }
  54.     }
  55.     }
  56. }
  57.  
  58. /* The disaster phase handles revolts, surrenders, accidents, and attrition. */
  59. /* Note that accidents and attrition happen even if unit changes sides. */
  60. /* Also, revolts happen first, so something that revolts may subsequently */
  61. /* surrender to nearby unit. */
  62.  
  63. disaster_phase()
  64. {
  65.     Unit *unit;
  66.  
  67.     if (Debug) printf("Entering disaster phase\n");
  68.     {
  69.     int u, t;
  70.  
  71.     for_all_unit_types(u) {
  72.         if (utypes[u].revolt > 0) anyrevolt = TRUE;
  73.         if (utypes[u].surrender > 0) anysurrender = TRUE;
  74.         for_all_terrain_types(t) {
  75.         if (utypes[u].accident[t] > 0) anyaccident = TRUE;
  76.         if (utypes[u].attrition[t] > 0) anyattrition = TRUE;
  77.         }
  78.     }
  79.     }
  80.     if (anyrevolt) {
  81.     for_all_units(unit) if (alive(unit)) unit_revolt(unit);
  82.     }
  83.     if (anysurrender) {
  84.     for_all_units(unit) if (alive(unit)) unit_surrender(unit);
  85.     }
  86.     if (anyaccident) {
  87.     for_all_units(unit) if (alive(unit)) unit_accident(unit);
  88.     }
  89.     if (anyattrition) {
  90.     for_all_units(unit) if (alive(unit)) unit_attrition(unit);
  91.     }
  92. }
  93.  
  94. /* A unit revolts by going back to its "true side" (which is usually set at */
  95. /* unit creation time).  The base revolt chance is worst case if morale is */
  96. /* variable; a unit at maximum (nonzero) morale will never revolt. */
  97.  
  98. unit_revolt(unit)
  99. Unit *unit;
  100. {
  101.     int u = unit->type, ux = unit->x, uy = unit->y, maxmor, chance;
  102.     Side *oldside = unit->side;
  103.  
  104.     if (utypes[unit->type].revolt > 0) {
  105.     chance = utypes[u].revolt;
  106.     maxmor = utypes[u].maxmorale;
  107.     if (maxmor > 0) chance = (chance * (maxmor - unit->morale)) / maxmor;
  108.     if (unit->trueside != oldside && random(10000) < chance) {
  109.         notify(oldside, "%s revolts!", unit_handle(oldside, unit));
  110.         unit_changes_side(unit, unit->trueside, CAPTURE, DISASTER);
  111.         if (see_exact(oldside, ux, uy))
  112.             draw_hex(oldside, ux, uy, TRUE);
  113.         all_see_hex(ux, uy);
  114.     }
  115.     }
  116. }
  117.  
  118. /* Units may also surrender to adjacent enemy units, but only to a type */
  119. /* that is both visible and capable of capturing the unit surrendering. */
  120. /* Neutrals have to be treated differently, since they don't have a view */
  121. /* to work from.  We sort of compute the view "on the fly". */
  122.  
  123. unit_surrender(unit)
  124. Unit *unit;
  125. {
  126.     bool surrounded = TRUE;
  127.     int u = unit->type, chance, d, x, y, view;
  128.     Unit *unit2, *eunit = NULL;
  129.     Side *us = unit->side, *es;
  130.  
  131.     if (utypes[u].surrender > 0 || utypes[u].siege > 0) {
  132.     chance = 0;
  133.     for_all_directions(d) {
  134.         x = wrap(unit->x + dirx[d]);  y = limit(unit->y + diry[d]);
  135.         if (neutral(unit)) {
  136.         if (((unit2 = unit_at(x, y)) != NULL) &&
  137.             (probability(utypes[unit2->type].visibility)) &&
  138.             (could_capture(unit2->type, u))) {
  139.             chance += utypes[u].surrender;
  140.             eunit = unit2;
  141.         } else {
  142.             surrounded = FALSE;
  143.         }
  144.         } else {
  145.         view = side_view(us, x, y);
  146.         if (view == EMPTY || view == UNSEEN) {
  147.             surrounded = FALSE;
  148.         } else {
  149.             es = side_n(vside(view));
  150.             if (enemy_side(us, es) && could_capture(vtype(view), u)) {
  151.             chance += utypes[u].surrender;
  152.             if (unit_at(x, y)) eunit = unit_at(x, y);
  153.             }
  154.         }
  155.         }
  156.     }
  157.     if (surrounded && eunit) chance += utypes[u].siege;
  158.     if (random(10000) < chance) {
  159.         if (eunit) {
  160.         notify(eunit->side, "%s has surrendered to you!",
  161.                unit_handle(eunit->side, unit));
  162.         notify(us, "%s has surrendered to the %s!",
  163.                unit_handle(us, unit), plural_form(eunit->side->name));
  164.         capture_unit(eunit, unit);
  165.         }
  166.     }
  167.     }
  168. }
  169.  
  170. /* Accidents will happen!... Kill off any occupants of course. */
  171.  
  172. unit_accident(unit)
  173. Unit *unit;
  174. {
  175.     int u = unit->type;
  176.     Side *us = unit->side;
  177.  
  178.     if (random(10000) < utypes[u].accident[terrain_at(unit->x, unit->y)]) {
  179.     if (strlen(utypes[u].accidentmsg) > 0)
  180.         notify(us, "%s %s!", unit_handle(us, unit), utypes[u].accidentmsg);
  181.     kill_unit(unit, DISASTER);
  182.     }
  183. }
  184.  
  185. /* Attrition only takes out a few hp at a time, but can be deadly... */
  186. /* Occupants lost only if unit lost (do we care?) */
  187.  
  188. unit_attrition(unit)
  189. Unit *unit;
  190. {
  191.     int u = unit->type;
  192.     Side *us = unit->side;
  193.  
  194.     if (random(10000) < utypes[u].attrition[terrain_at(unit->x, unit->y)]) {
  195.     if (unit->hp <= utypes[u].attdamage) {
  196.         notify(us, "%s dies from attrition!", unit_handle(us, unit));
  197.         kill_unit(unit, DISASTER);
  198.     } else {
  199.         if (strlen(utypes[u].attritionmsg) > 0) {
  200.         notify(us, "%s %s!",
  201.                unit_handle(us, unit), utypes[u].attritionmsg);
  202.         }
  203.         unit->hp -= utypes[u].attdamage;
  204.     }
  205.     }
  206. }
  207.  
  208. /* Repair always proceeds each turn, as long as the repairing unit is not */
  209. /* crippled.  A unit can repair itself, its transport, and its occupants. */
  210.  
  211. /* Another activity of units is to build other units.  The code here has to */
  212. /* be a little tricky because players need to get opportunities to cancel */
  213. /* and to idle units, plus not get asked about units that don't usually */
  214. /* produce things. */
  215.  
  216. /* The order of repair vs building means scarce supplies used on existing */
  217. /* units first. */
  218.  
  219. build_phase()
  220. {
  221.     Unit *unit, *occ;
  222.  
  223.     if (Debug) printf("Entering build phase\n");
  224.     for_all_units(unit) {
  225.     if (alive(unit) && !cripple(unit)) {
  226.         repair_unit(unit, unit);
  227.         for_all_occupants(unit, occ) repair_unit(unit, occ);
  228.         if (unit->transport != NULL) repair_unit(unit, unit->transport);
  229.         work_on_new_unit(unit);
  230.     }
  231.     }
  232. }
  233.  
  234. /* One arbitrary unit repairs another only if actually needed.  Rate is */
  235. /* always less than 1 hp/turn; this is a practical limit on max hp values */
  236. /* if reasonably rapid repair is desired.  If unit being repaired was badly */
  237. /* damaged (crippled), then we'll use up same resources as needed for */
  238. /* construction, and if a resource type is missing, then repairs will not */
  239. /* proceed at all. */
  240.  
  241. repair_unit(unit, unit2)
  242. Unit *unit, *unit2;
  243. {
  244.     int u = unit->type, u2 = unit2->type, r;
  245.  
  246.     if ((unit2->hp < utypes[u2].hp) && could_repair(u, u2)) {
  247.     if ((global.time % utypes[u].repair[u2]) == 0) {
  248.         if (cripple(unit2)) {
  249.         for_all_resource_types(r) {
  250.             if (unit->supply[r] < utypes[u2].tomake[r]) return;
  251.         }
  252.         for_all_resource_types(r) {
  253.             unit->supply[r] -= utypes[u2].tomake[r] / utypes[u2].hp;
  254.         }
  255.         }
  256.         unit2->hp++;
  257.     }
  258.     }
  259. }
  260.  
  261. /* Machine players need opportunities to change their production. */
  262. /* Neutrals never produce (what could they do with the results?). */
  263. /* Construction may be constrained by lack of resources, so don't count */
  264. /* down on schedule or use up building materials unless we actually have */
  265. /* enough. */
  266.  
  267. work_on_new_unit(unit)
  268. Unit *unit;
  269. {
  270.     int u = unit->type, r, mk, rmk, use;
  271.     
  272.     if (!neutral(unit)) {
  273.     if (producing(unit)) {
  274.         mk = utypes[u].make[unit->product];
  275.         for_all_resource_types(r) {
  276.         if ((rmk = utypes[unit->product].tomake[r]) > 0) {
  277.             use = (rmk / mk) + (unit->schedule < (rmk % mk) ? 1 : 0);
  278.             if (unit->supply[r] < use) return;
  279.             unit->supply[r] -= use;
  280.         }
  281.         }
  282.         unit->schedule--;
  283.         if (unit->schedule <= 0) {
  284.         if (complete_new_unit(unit, unit->product)) {
  285.             if (!utypes[u].maker) {
  286.             set_product(unit, NOTHING);
  287.             } else {
  288.             set_schedule(unit);
  289.             }
  290.         } else {
  291.             unit->schedule++;
  292.         }
  293.         }
  294.     } else {
  295.         if (unit->schedule > 0) unit->schedule--;
  296.     }
  297.     }
  298. }
  299.  
  300. /* When one unit produces another, it may be that one can occupy the other, */
  301. /* in either direction.  So we have to make sure that both ways work. */
  302. /* Also the builder may become the garrison, so we have to get it out of */
  303. /* the way before deciding about fiddling around. */
  304. /* Morale of new unit is slightly more than morale of building unit. */
  305. /* Returns success of the whole process. */
  306.  
  307. complete_new_unit(unit, type)
  308. Unit *unit;
  309. int type;
  310. {
  311.     bool success = FALSE;
  312.     int ux = unit->x, uy = unit->y;
  313.     Unit *mainunit, *newunit;
  314.     Side *us = unit->side;
  315.  
  316.     if (will_garrison(unit->type, type)) leave_hex(unit);
  317.     if ((newunit = create_unit(type, NULL)) != NULL) {
  318.     mainunit = unit_at(ux, uy);
  319.     if (mainunit == NULL) {
  320.         if (could_occupy(type, terrain_at(ux, uy))) {
  321.         assign_unit_to_side(newunit, us);
  322.         occupy_hex(newunit, ux, uy);
  323.         success = TRUE;
  324.         } else {
  325.         notify(us, "%s can't go here!", unit_handle(us, newunit));
  326.         kill_unit(newunit, DISASTER);
  327.         }
  328.     } else if (could_carry(mainunit->type, type)) {
  329.         if (can_carry(mainunit, newunit)) {
  330.         assign_unit_to_side(newunit, us);
  331.         occupy_hex(newunit, ux, uy);
  332.         success = TRUE;
  333.         } else {
  334.         notify(us, "%s will delay completion of %s until it has room.",
  335.                unit_handle(us, unit), utypes[type].name);
  336.         kill_unit(newunit, DISASTER);
  337.         }
  338.     } else if (could_carry(type, mainunit->type)) {
  339.         if (could_occupy(type, terrain_at(ux, uy))) {
  340.         assign_unit_to_side(newunit, us);
  341.         occupy_hex(newunit, ux, uy);
  342.         success = TRUE;
  343.         } else {
  344.         notify(us, "%s can't go here!", unit_handle(us, newunit));
  345.         kill_unit(newunit, DISASTER);
  346.         }
  347.     } else {
  348.         notify(us, "Idiots! - %s can't build a %s while in a %s!",
  349.            unit_handle(us, unit),
  350.            utypes[type].name, utypes[mainunit->type].name);
  351.         kill_unit(newunit, DISASTER);
  352.     }
  353.     }
  354.     if (will_garrison(unit->type, type)) occupy_hex(unit, ux, uy);
  355.     if (success) {
  356.     if (utypes[type].named) newunit->name = make_unit_name(newunit);
  357.     newunit->morale = min(newunit->morale, unit->morale + 1);
  358.     unit->built++;
  359.     (us->balance[type][PRODUCED])++;
  360.     (us->units[type])++;
  361.     if (will_garrison(unit->type, type)) kill_unit(unit, GARRISON);
  362.     update_state(us, type);
  363.     if (Debug) printf("%s is completed\n", unit_handle(NULL, newunit));
  364.     }
  365.     return success;
  366. }
  367.  
  368. /* The main routine does production, distribution, and discarding in order. */
  369.  
  370. supply_phase()
  371. {
  372.     int u, r, t, amt, dist, x, y, x1, y1, x2, y2;
  373.     Unit *unit, *ounit, *occ;
  374.  
  375.     if (Debug) printf("Entering supply phase\n");
  376.     /* Make new resources but don't clip to storage capacity yet */
  377.     for_all_units(unit) {
  378.     u = unit->type;
  379.     for_all_resource_types(r) {
  380.         t = terrain_at(unit->x, unit->y);
  381.         amt = (utypes[u].produce[r] * utypes[u].productivity[t]) / 100;
  382.         if (cripple(unit))
  383.         amt = (amt * unit->hp) / (utypes[u].crippled + 1);
  384.         unit->supply[r] += amt;
  385.     }
  386.     }
  387.     /* Move stuff around - hopefully will get rid of any excess */
  388.     for_all_units(unit) {
  389.     for_all_resource_types(r) {
  390.             dist = utypes[unit->type].outlength[r];
  391.         y1 = unit->y - dist;
  392.         y2 = unit->y + dist;
  393.         for (y = y1; y <= y2; ++y) {
  394.         if (between(0, y, world.height-1)) {
  395.             x1 = unit->x - (y < unit->y ? (y - y1) : dist);
  396.             x2 = unit->x + (y > unit->y ? (y2 - y) : dist);
  397.             for (x = x1; x <= x2; ++x) {
  398.             ounit = unit_at(wrap(x), y);
  399.             if (ounit != NULL && alive(ounit) &&
  400.                 ounit->side == unit->side) {
  401.                 try_transfer(unit, ounit, r);
  402.                 for_all_occupants(ounit, occ)
  403.                 try_transfer(unit, occ, r);
  404.             }
  405.             }
  406.         }
  407.         }
  408.     }
  409.     }
  410.     /* Throw away any excess */
  411.     for_all_units(unit) {
  412.     u = unit->type;
  413.     for_all_resource_types(r) {
  414.         unit->supply[r] = min(unit->supply[r], utypes[u].storage[r]);
  415.     }
  416.     }
  417. }
  418.  
  419. /* The middle subphase of supply uses this routine to move supplies around */
  420. /* between units far apart or on the same hex. */
  421.  
  422. try_transfer(from, to, r)
  423. Unit *from, *to;
  424. int r;
  425. {
  426.     int nd;
  427.  
  428.     if (from == to) return;
  429.     if (utypes[to->type].inlength[r] >=
  430.     distance(from->x, from->y, to->x, to->y)) {
  431.     if ((nd = utypes[to->type].storage[r] - to->supply[r]) > 0) {
  432.         if (can_satisfy_need(from, r, nd)) {
  433.         transfer_supply(from, to, r, nd);
  434.         } else if (can_satisfy_need(from, r, max(1, nd/2))) {
  435.         transfer_supply(from, to, r, max(1, nd/2));
  436.         }
  437.     }
  438.     }
  439. }
  440.  
  441. /* This estimates what can be spared.  Note that total transfer of requested */
  442. /* amount is not a good idea, since the supplies might be essential to the */
  443. /* unit that has them first.  If we're more than half full, or the request */
  444. /* is less than 1/5 of our supply, then we can spare it. */
  445.  
  446. can_satisfy_need(unit, r, need)
  447. Unit *unit;
  448. int r, need;
  449. {
  450.     return (((2 * unit->supply[r]) > (utypes[unit->type].storage[r])) ||
  451.         (need < (utypes[unit->type].storage[r] / 5)));
  452. }
  453.  
  454. /* Move supply from one unit to another.  Don't move more than is possible; */
  455. /* check both from and to amounts and capacities. */
  456.  
  457. transfer_supply(from, to, r, amount)
  458. Unit *from, *to;
  459. int r, amount;
  460. {
  461.     amount = min(amount, from->supply[r]);
  462.     amount = min(amount, utypes[to->type].storage[r] - to->supply[r]);
  463.     from->supply[r] -= amount;
  464.     to->supply[r] += amount;
  465.     if (Debug) printf("%s receives %d %s\n",
  466.               unit_handle(NULL, to), amount, rtypes[r].name);
  467.     return amount;
  468. }
  469.  
  470. /* Handle constant consumption, which is a post process to movement. */
  471. /* Don't care about current side in this phase.  This is also a handy */
  472. /* place to count up all of a side's resources, for use by win/lose tests. */
  473.  
  474. consumption_phase()
  475. {
  476.     int r;
  477.     Unit *unit;
  478.     Side *side;
  479.  
  480.     if (Debug) printf("Entering consumption phase\n");
  481.     for_all_sides(side) {
  482.     for_all_resource_types(r) {
  483.         side->resources[r] = 0;
  484.     }
  485.     }
  486.     for_all_units(unit) if (alive(unit)) unit_consumes(unit);
  487. }
  488.  
  489. /* Consume the constant overhead part of supply consumption. */
  490. /* Usage by movement is subtracted from overhead first. */
  491. /* Finally, credit side with the unit's remaining supplies. */
  492.  
  493. unit_consumes(unit)
  494. Unit *unit;
  495. {
  496.     int u = unit->type, r, usedup;
  497.     
  498.     for_all_resource_types(r) {
  499.     if (utypes[u].consume[r] > 0) {
  500.         usedup = unit->actualmoves * utypes[u].tomove[r];
  501.         if (usedup < utypes[u].consume[r])
  502.         unit->supply[r] -= (utypes[u].consume[r] - usedup);
  503.         if (unit->supply[r] <= 0 && !in_supply(unit)) {
  504.         exhaust_supply(unit);
  505.         return;
  506.         }
  507.     }
  508.     if (!neutral(unit)) unit->side->resources[r] += unit->supply[r];
  509.     }
  510. }
  511.  
  512. /* What happens to a unit that runs out of a supply.  If it can survive */
  513. /* on no supplies, then there may be a few turns of grace, depending on */
  514. /* how the dice roll... */
  515.  
  516. exhaust_supply(unit)
  517. Unit *unit;
  518. {
  519.     if (probability(100 - utypes[unit->type].survival)) {
  520.     notify(unit->side, "%s %s!",
  521.            unit_handle(unit->side, unit), utypes[unit->type].starvemsg);
  522.     kill_unit(unit, STARVATION);
  523.     }
  524. }
  525.  
  526. /* Check if the unit has ready access to a source of supplies. */
  527.  
  528. in_supply(unit)
  529. Unit *unit;
  530. {
  531.     if (unit->transport != NULL) return TRUE;
  532.     /* needs to be more sophisticated and account for supply lines */
  533.     return FALSE;
  534. }
  535.